/* Copyright (C) 2008, 2009, 2010 Faindu GmbH, Switzerland.
* All Rights Reserved. The following is Source Code and is subject to all restrictions 
* on such code as contained in the license accompanying this project. */
package blocstac.editimage.base
{
	import blocstac.util.CreateLogger;
	
	import mx.logging.ILogger;

	
public class UndoManager
{
	
	function UndoManager(canUndoRedoChanged:Function) {
		_canUndoRedoChanged = canUndoRedoChanged
	}
	
	private static const LOG:ILogger = CreateLogger.withClassNameOf(UndoManager)
	private var _canUndoRedoChanged:Function
	private var _undoStack:Vector.<ImageOperation> = new Vector.<ImageOperation>
	private var _redoStack:Vector.<ImageOperation> = new Vector.<ImageOperation>
	private var _initUndoStackLength:uint
	private var _initRedoStackLength:uint
		
	private function addToUndoStack(op:ImageOperation):void {
		_undoStack.push(op)
		if (_undoStack.length > 10) {
			_undoStack.shift()
		}
	}
	
	private function addToRedoStack(op:ImageOperation):void {
		_redoStack.unshift(op)
		if (_redoStack.length > 10) {
			_redoStack.pop()
		}
	}
	
	private function initChanges():void {
		_initUndoStackLength = _undoStack.length
		_initRedoStackLength = _redoStack.length
	}
	
	private function checkForChanges():void {
		var undoLength:uint = _undoStack.length
		var redoLength:uint = _redoStack.length
		if (_initUndoStackLength == 0 && undoLength > 0 || 
			_initUndoStackLength > 0 && undoLength == 0 ||
			_initRedoStackLength == 0 && redoLength > 0 ||
			_initRedoStackLength > 0 && redoLength == 0) {
			_canUndoRedoChanged()
		}
	}
	
	public function addOperation(op:ImageOperation):void {
		initChanges()
		if (op) {
			addToUndoStack(op)
			_redoStack.length = 0
		}
		checkForChanges()
	}
	
	public function undo(state:ImageModel):Boolean {
		initChanges()
		var undoSuccessful:Boolean
		var op:ImageOperation = _undoStack.pop()
		if (op) {
			op.undo(state)
			addToRedoStack(op)
			undoSuccessful = true
		}
		checkForChanges()
		return undoSuccessful
	}

	public function redo(state:ImageModel):Boolean {
		initChanges()
		var redoSuccessful:Boolean
		var op:ImageOperation = _redoStack.shift()
		if (op) {
			op.apply(state)
			addToUndoStack(op)
			redoSuccessful = true
		}
		checkForChanges()
		return redoSuccessful
	}
	
	public function canUndo():Boolean {
		return _undoStack.length > 0
	}
	
	public function canRedo():Boolean {
		return _redoStack.length > 0
	}

	public function reset():void {
		initChanges()
		_undoStack.length = 0
		_redoStack.length = 0
		checkForChanges()
	}
}
}